home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / memory / mtlxms21 / xms.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-14  |  14.8 KB  |  559 lines

  1. //--------------------------------------------------------------------------
  2. //
  3. //      XMS.CPP: body of XMS interface library.
  4. //      Copyright (c) J.English 1993.
  5. //      Author's address: je@unix.brighton.ac.uk
  6. //
  7. //      Permission is granted to use copy and distribute the
  8. //      information contained in this file provided that this
  9. //      copyright notice is retained intact and that any software
  10. //      or other document incorporating this file or parts thereof
  11. //      makes the source code for the library of which this file
  12. //      is a part freely available.
  13. //
  14. // MODIFIED BY MAXTAL PTY LTD
  15. //--------------------------------------------------------------------------
  16. //
  17. //      Revision history:
  18. //      2.0     Nov 1993        Initial coding
  19. //      2.1     Aug 1994        Modified to handle odd no of bytes
  20. //                              Added routine to get # of available handles
  21. //
  22. // COMMENT: Note the "clever" way the block byte move functions
  23. // call the one byte move functions if they have to move an odd number of
  24. // bytes, which in turn call the block move functions again!
  25. //--------------------------------------------------------------------------
  26.  
  27. #include "xms.h"
  28. #include <dos.h>
  29. #include <mem.h>
  30. #include <stdlib.h>
  31.  
  32. //--------------------------------------------------------------------------
  33. //
  34. //      Data structure declarations.
  35. //
  36. struct XMSmove              // descriptor for XMS moves
  37. {
  38.     long count;             // ... number of bytes to move
  39.     int  srchandle;         // ... source handle (0 for real memory)
  40.     long srcoffset;         // ... source offset (or far pointer)
  41.     int  dsthandle;         // ... destination handle (0 for real memory)
  42.     long dstoffset;         // ... destination offset (or far pointer)
  43. };
  44.  
  45.  
  46. //--------------------------------------------------------------------------
  47. //
  48. //      Constants.
  49. //
  50. const long K    = 1024;     // size of a kilobyte in bytes
  51. const int  PARA = 16;       // size of a paragraph in bytes
  52.  
  53.  
  54. //--------------------------------------------------------------------------
  55. //
  56. //      Globals (statics).
  57. //
  58. static void far (*XMSdriver)() = 0;     // pointer to XMS driver routine
  59. static int      XMSinited      = 0;     // has XMSinit been called already?
  60. static XMSmove  descriptor;             // why use more than one?
  61. static int      A20enabled;             // original A20 state
  62.  
  63. //--------------------------------------------------------------------------
  64. //
  65. //      XMSinit: initialise XMS system (first time only).
  66. //
  67. //      The first time it is called, this function locates the XMS driver
  68. //      and allocates a handle for a zero-byte block.  It returns TRUE if
  69. //      a handle was successfully allocated.  Subsequent calls return the
  70. //      same value.
  71. //
  72. static XMS::error XMSinit ()
  73. {
  74.     //--- check if this is the first time XMSinit has been called
  75.     if (XMSinited == 0)
  76.     {
  77.         //--- now it isn't!
  78.         XMSinited = 1;
  79.  
  80.         //--- check if an XMS driver is present (magic spell)
  81.         REGS r;
  82.         r.x.ax = 0x4300;
  83.         int86 (0x2F, &r, &r);
  84.         if (r.h.al != 0x80)
  85.             return XMS::NO_DRIVER;
  86.  
  87.         //--- get the XMS driver's address (magic spell)
  88.         SREGS s;
  89.         r.x.ax = 0x4310;
  90.         int86x (0x2F, &r, &r, &s);
  91.         XMSdriver = (void far (*)()) MK_FP(s.es,r.x.bx);
  92.     }
  93.  
  94.     //--- return success indicator
  95.     return (XMSdriver != 0 ? XMS::SUCCESS : XMS::NO_DRIVER);
  96. }
  97.  
  98.  
  99. //--------------------------------------------------------------------------
  100. //
  101. //      XMScopy: copy block to/from XMS.
  102. //
  103. //      This function copies data in accordance with the parameters set
  104. //      up in the structure "descriptor".  Overlapping blocks may not be
  105. //      handled correctly (as per XMS specification).  It does nothing if
  106. //      XMS initialisation fails.
  107. //
  108. static XMS::error XMScopy ()
  109. {
  110.     XMS::error result = XMSinit ();
  111.     if (result == XMS::SUCCESS)
  112.     {   _SI = FP_OFF (&descriptor);
  113.         _AH = 0x0B;
  114.         XMSdriver ();
  115.         if (_AX == 0)
  116.             result = XMS::error (_BL);
  117.     }
  118.     return result;
  119. }
  120.  
  121. //--------------------------------------------------------------------------
  122. //
  123. //      XMS::XMS.
  124. //
  125. //      Constructor for class XMS.  Initialises XMSdriver if necessary,
  126. //      and attempts to allocate a block of the specified number of bytes
  127. //      (which will be rounded up to the nearest K).
  128. //
  129. XMS::XMS (long size)
  130. {
  131.     handle = 0;
  132.     allocation = 0;
  133.     if ((status = XMSinit()) == SUCCESS)
  134.     {   int result = 0;
  135.         int realsize;
  136.         size += K - 1;
  137.         int request = size / K;
  138.         _DX = request;
  139.         _AH = 0x09;
  140.         XMSdriver ();
  141.         result = _AX;
  142.         if (result)
  143.         {   handle = _DX;
  144.             _AH = 0x0E;
  145.             XMSdriver ();
  146.             result = _AX;
  147.             realsize = _DX;
  148.         }
  149.         else
  150.             status = error (_BL);
  151.         if (result)
  152.             allocation = realsize * K;
  153.     }
  154. }
  155.  
  156.  
  157. //--------------------------------------------------------------------------
  158. //
  159. //      XMS::~XMS: release the XMS handle (if any).
  160. //
  161. XMS::~XMS ()
  162. {
  163.     if (handle)
  164.     {   _DX = handle;
  165.         _AH = 0x0A;
  166.         XMSdriver ();
  167.     }
  168. }
  169.  
  170. //--------------------------------------------------------------------------
  171. //
  172. //      XMS::resize.
  173. //
  174. //      Resize existing XMS allocation.
  175. //
  176. XMS::error XMS::resize (long newsize)
  177. {
  178.     error result = (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  179.     int size;
  180.     if (handle)
  181.     {   result = SUCCESS;
  182.         newsize += K - 1;
  183.         int request = newsize / K;
  184.         _DX = handle;
  185.         _BX = request;
  186.         _AH = 0x0F;
  187.         XMSdriver ();
  188.         if (_AX != 0)
  189.         {   _DX = handle;
  190.             _AH = 0x0E;
  191.             XMSdriver ();
  192.             size = _DX;
  193.         }
  194.         if (_AX != 0)
  195.             allocation = size * K;
  196.         else
  197.             result = error (_BL);
  198.     }
  199.     return result;
  200. }
  201.  
  202.  
  203. //MAXTAL: NEW ONE BYTE MOVE----------------------------------------------
  204. // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
  205. unsigned char XMS :: get (const XMS :: XMSptr & x)
  206. {
  207.   unsigned char buffer [2];
  208.   XMS :: copy (buffer, x, 2);
  209.   return buffer [0];
  210. }
  211.  
  212. //MAXTAL: NEW ONE BYTE MOVE----------------------------------------------
  213. // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
  214. void XMS :: put (const XMS :: XMSptr & x, unsigned char ch)
  215. {
  216.   unsigned char buffer [2];
  217.   XMS :: copy (buffer, x, 2);
  218.   // get
  219.   buffer [0] = ch;
  220.   XMS :: copy (x, buffer, 2);
  221.   // put
  222. }
  223.  
  224. //MAXTAL: MODIFIED----------------------------------------------------------
  225. //
  226. //      XMS::at.
  227. //
  228. //      Returns a descriptor identifying a particular byte offset in a
  229. //      particular XMS object for use in the "copy" operations below.
  230. //
  231. XMS::XMSptr XMS::at (long offset)
  232. {
  233.     XMSptr p(handle, offset); //MAXTAL
  234.     return p;
  235. }
  236.  
  237. //MAXTAL: MODIFIED TO HANDLE ODD NO OF BYTES--------------------------------
  238. // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
  239. //
  240. //      XMS::copy.
  241. //
  242. //      Copy from XMS to XMS.
  243. //
  244. XMS::error XMS::copy (const XMS::XMSptr& to,
  245.                       const XMS::XMSptr& from,
  246.                       unsigned len)
  247. {
  248.     if (from.handle == 0 || to.handle == 0)
  249.         return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  250.  
  251.     error result = SUCCESS;
  252.     unsigned long evens = len & ~1UL;
  253.     int odds = len & 1;
  254.     if (evens != 0)
  255.     {
  256.         descriptor.count = evens;
  257.         descriptor.srchandle = from.handle;
  258.         descriptor.srcoffset = from.offset;
  259.         descriptor.dsthandle = to.handle;
  260.         descriptor.dstoffset = to.offset;
  261.         result = XMScopy();
  262.     }
  263.     if (odds)
  264.         put (to [len - 1], get (from [len - 1] ) );
  265.     return result;
  266. }
  267.  
  268.  
  269. //MAXTAL: MODIFIED TO HANDLE ODD NO OF BYTES--------------------------------
  270. // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
  271. //
  272. //      XMS::copy.
  273. //
  274. //      Copy from XMS to conventional memory.
  275. //
  276. XMS::error XMS::copy (void far* to,
  277.                       const XMS::XMSptr& from,
  278.                       unsigned len)
  279. {
  280.     if (from.handle == 0)
  281.         return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  282.     error result=SUCCESS;
  283.     unsigned long evens = len & ~1UL;
  284.     int odds = len & 1;
  285.     if (evens != 0)
  286.     {
  287.         descriptor.count = evens;
  288.         descriptor.srchandle = from.handle;
  289.         descriptor.srcoffset = from.offset;
  290.         descriptor.dsthandle = 0;
  291.         descriptor.dstoffset = long (to);
  292.         result = XMScopy ();
  293.     }
  294.     if (odds)
  295.         * ( (char huge * ) to + len - 1) = get (from [len - 1] );
  296.     return result;
  297. }
  298.  
  299.  
  300. //MAXTAL: MODIFIED TO HANDLE ODD NO OF BYTES--------------------------------
  301. // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
  302. //
  303. //      XMS::copy.
  304. //
  305. //      Copy from conventional memory to XMS.
  306. //
  307. XMS::error XMS::copy (const XMS::XMSptr& to,
  308.                       void far* from,
  309.                       unsigned len)
  310. {
  311.     if (to.handle == 0)
  312.         return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  313.     error result = SUCCESS;
  314.     unsigned long evens = len & ~1UL;
  315.     int odds = len & 1;
  316.     if (evens != 0)
  317.     {
  318.         descriptor.count = evens;
  319.         descriptor.srchandle = 0;
  320.         descriptor.srcoffset = (unsigned long) (from);
  321.         descriptor.dsthandle = to.handle;
  322.         descriptor.dstoffset = to.offset;
  323.         result = XMScopy ();
  324.     }
  325.     if (odds)
  326.         put (to[len-1], * ( (char huge * ) from + len - 1) );
  327.     return result;
  328. }
  329.  
  330. //--------------------------------------------------------------------------
  331. //
  332. //      XMS::available.
  333. //
  334. //      Returns the total size of available XMS.
  335. //
  336. long XMS::available ()
  337. {
  338.     if (XMSinit () == SUCCESS)
  339.     {   _AH = 0x08;
  340.         XMSdriver ();
  341.         return _DX * K;
  342.     }
  343.     else
  344.         return 0;
  345. }
  346.  
  347.  
  348. //--------------------------------------------------------------------------
  349. //
  350. //      XMS::largest.
  351. //
  352. //      Returns the size of the largest unallocated XMS block available.
  353. //
  354. long XMS::largest ()
  355. {
  356.     if (XMSinit () == SUCCESS)
  357.     {   _AH = 0x08;
  358.         XMSdriver ();
  359.         return _AX * K;
  360.     }
  361.     else
  362.         return 0;
  363. }
  364. //MAXTAL: NEW-------------------------------------------------------------
  365. //
  366. //      XMS::havail
  367. //
  368. //      Returns the number of available handles
  369. //
  370. unsigned long XMS :: havail ()
  371. {
  372.     XMSinit ();
  373.     _AH = 0x0E;
  374.     _DX = 0;
  375.     XMSdriver ();
  376.     return _BL;
  377. }
  378.  
  379.  
  380. //--------------------------------------------------------------------------
  381. //
  382. //      UMB::UMB.
  383. //
  384. //      Attempt to construct a UMB block of the specified size.
  385. //
  386. UMB::UMB (long size)
  387. {
  388.     address = 0;
  389.     allocation = 0;
  390.     if (size > (64 * K - 1) * PARA)
  391.         status = XMS::BLOCK_TOO_BIG;
  392.     else if ((status = XMSinit()) == XMS::SUCCESS)
  393.     {   size += PARA - 1;
  394.         _DX = unsigned (size/PARA);
  395.         _AH = 0x10;
  396.         XMSdriver ();
  397.         if (_AX != 0)
  398.         {   int bx = _BX;
  399.             address = MK_FP (bx,0);
  400.             allocation = unsigned (_DX);
  401.         }
  402.         else
  403.             status = XMS::error (_BL);
  404.     }
  405.     allocation *= PARA;
  406. }
  407.  
  408.  
  409. //--------------------------------------------------------------------------
  410. //
  411. //      UMB::~UMB.
  412. //
  413. //      Destroy UMB block if it has been created successfully.
  414. //
  415. UMB::~UMB ()
  416. {
  417.     if (address != 0)
  418.     {   _DX = FP_SEG (address);
  419.         _AH = 0x11;
  420.         XMSdriver ();
  421.     }
  422. }
  423.  
  424.  
  425. //--------------------------------------------------------------------------
  426. //
  427. //      UMB::largest.
  428. //
  429. //      Return size of largest available UMB block.
  430. //
  431. long UMB::largest ()
  432. {
  433.     long size = 0;
  434.     if (XMSinit () == XMS::SUCCESS)
  435.     {   _AH = 0x10;
  436.         _DX = 0xFFFF;
  437.         XMSdriver ();
  438.         size = unsigned (_DX);
  439.     }
  440.     return size * PARA;
  441. }
  442.  
  443. //--------------------------------------------------------------------------
  444. //
  445. //      HMA::HMA.
  446. //
  447. //      Attempt to allocate HMA for a block of the specified size.
  448. //
  449. HMA::HMA (unsigned size)
  450. {
  451.     allocation = 0;
  452.     if (size > (64 * K) - PARA)
  453.         status = XMS::BLOCK_TOO_BIG;
  454.     else if ((status = XMSinit()) == XMS::SUCCESS)
  455.     {   _DX = size;
  456.         _AH = 0x01;
  457.         XMSdriver ();
  458.         if (_AX != 0)
  459.         {   allocation = size;
  460.             _AH = 0x07;
  461.             XMSdriver ();
  462.             A20enabled = _AX;
  463.             if (!A20enabled)
  464.             {   _AH = 0x03;
  465.                 XMSdriver ();
  466.                 if (_AX != 0)
  467.                     return;
  468.             }
  469.         }
  470.         status = XMS::error (_BL);
  471.     }
  472. }
  473.  
  474.  
  475. //--------------------------------------------------------------------------
  476. //
  477. //      HMA::~HMA.
  478. //
  479. //      Release HMA if it has been allocated successfully.
  480. //
  481. HMA::~HMA ()
  482. {
  483.     if (status == XMS::SUCCESS)
  484.     {   _AH = 0x02;
  485.         XMSdriver ();
  486.         if (!A20enabled)
  487.         {   _AH = 0x04;
  488.             XMSdriver ();
  489.             A20enabled = !_AX;
  490.         }
  491.     }
  492. }
  493.  
  494.  
  495. //--------------------------------------------------------------------------
  496. //
  497. //      HMA::at.
  498. //
  499. HMA::HMAptr HMA::at (unsigned offset)
  500. {
  501.     HMAptr h = { this, offset };
  502.     return h;
  503. }
  504.  
  505. //--------------------------------------------------------------------------
  506. //
  507. //      HMA::copy.
  508. //
  509. //      Copy a block from one offset in the HMA to another.  The two
  510. //      blocks should not overlap.
  511. //
  512. unsigned HMA::copy (const HMAptr& to, const HMAptr& from, unsigned len)
  513. {
  514.     if (!to.hma->valid() || !from.hma->valid())
  515.         return 0;
  516.     if (len > to.hma->size() - to.offset)
  517.         len = to.hma->size() - to.offset;
  518.     if (len > from.hma->size() - from.offset)
  519.         len = from.hma->size() - from.offset;
  520.     _fmemcpy (MK_FP (0xFFFF, 0x0010 + to.offset),
  521.               MK_FP (0xFFFF, 0x0010 + from.offset),
  522.               len);
  523.     return len;
  524. }
  525.  
  526.  
  527. //--------------------------------------------------------------------------
  528. //
  529. //      HMA::copy.
  530. //
  531. //      Copy a block from the HMA to conventional memory.
  532. //
  533. unsigned HMA::copy (void far* to, const HMAptr& from, unsigned len)
  534. {
  535.     if (!from.hma->valid())
  536.         return 0;
  537.     if (len > from.hma->size() - from.offset)
  538.         len = from.hma->size() - from.offset;
  539.     _fmemcpy (to, MK_FP (0xFFFF, 0x0010 + from.offset), len);
  540.     return len;
  541. }
  542.  
  543.  
  544. //--------------------------------------------------------------------------
  545. //
  546. //      HMA::copy.
  547. //
  548. //      Copy a block from conventional memory to the HMA.
  549. //
  550. unsigned HMA::copy (const HMAptr& to, void far* from, unsigned len)
  551. {
  552.     if (!to.hma->valid())
  553.         return 0;
  554.     if (len > to.hma->size() - to.offset)
  555.         len = to.hma->size() - to.offset;
  556.     _fmemcpy (MK_FP (0xFFFF, 0x0010 + to.offset), from, len);
  557.     return len;
  558. }
  559.